package com.ruoyi.pm.util;

import com.fasterxml.jackson.databind.JsonNode;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.pubfun.JsonMapper;
import com.ruoyi.pm.util.ExcConstant.DecodeKey;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * 数据转换通用工具类
 *
 * @author xiongyw
 * @time 2016年12月19日上午11:41:10
 * @Company 优法云
 */
public class ExchangeUtil {

    protected static Logger logger = LoggerFactory.getLogger(ExchangeUtil.class);

    public static String readRequest(HttpServletRequest request) {
        String bodyStr = null;
        // 通过request获取里面的数据信息
        try {
            InputStream is = request.getInputStream();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte buff[] = new byte[1024];
            int read;
            while ((read = is.read(buff)) > 0) {
                baos.write(buff, 0, read);
            }
            bodyStr = new String(baos.toByteArray(), "utf-8");
            baos.close();
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bodyStr;
    }

    /**
     * xml转化为json
     *
     * @param xml
     * @return
     */
    public static String xmlToJson(String xml) {
        if (xml == null || xml.startsWith("{")) {
            //增加后面的判断是可能传输过来的是json
            return null;
        }
        try {
            Document document = DocumentHelper.parseText(xml);
            return JsonMapper.toJsonString(documentToMap(document.getRootElement(), new TreeMap<String, Object>()));
        } catch (DocumentException e) {
            // 构造一个StringBuilder对象
            StringBuilder sb = new StringBuilder(xml);
            // 如果是转化失败，那么可能存在没有根节点的问题,这个地方可能有问题，下次用正则处理
            int index = xml.indexOf("?>");
            if (index < 0) {
                index = 0;
            }
            sb.insert(index, "<" + DecodeKey.RootName + ">");
            sb.append("</" + DecodeKey.RootName + ">");
            xml = sb.toString();
            try {
                Document document = DocumentHelper.parseText(xml);
                return JsonMapper.toJsonString(documentToMap(document.getRootElement(), new TreeMap<String, Object>())
                        .get(DecodeKey.RootName));
            } catch (DocumentException e1) {
                e1.printStackTrace();
            }
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    private static Map<String, Object> documentToMap(Element rootElement, Map<String, Object> resultMap) {
        List<Element> childrenList = rootElement.elements();

        for (Element element : childrenList) {
            if (element.elements().isEmpty()) {
                resultMap.put(element.getName(), element.getStringValue());
            } else {
                if (resultMap.containsKey(element.getName())) {
                    // 说明意境有该key的存在，那么我们需要当作list处理
                    Object value = resultMap.get(element.getName());
                    List<Map<String, Object>> valueList = null;
                    if (value instanceof Map) {
                        valueList = new ArrayList<>();
                        valueList.add((Map<String, Object>) value);
                        resultMap.remove(element.getName());
                        resultMap.put(element.getName(), valueList);
                    } else {
                        valueList = (List<Map<String, Object>>) value;
                    }
                    Map<String, Object> cMap = new TreeMap<>();
                    documentToMap(element, cMap);
                    valueList.add(cMap);
                } else {
                    Map<String, Object> cMap = new TreeMap<>();
                    documentToMap(element, cMap);
                    resultMap.put(element.getName(), cMap);
                }
            }
        }

        Map<String, Object> rootMap = new TreeMap<>();
        rootMap.put(rootElement.getName(), resultMap);
        return rootMap;
    }

    public static String jsonToXml(String json) {
        return jsonToXml(json, "UTF-8", true);
    }

    public static String jsonToXml(String json, String charset) {
        return jsonToXml(json, charset, true);
    }

    public static String jsonToXml(String json, boolean headerFlag) {
        return jsonToXml(json, "UTF-8", headerFlag);
    }

    public static String jsonToXml(String json, String charset, boolean headerFlag) {
        if (StringUtils.isBlank(charset)) {
            charset = "UTF-8";
        }
        if (json == null || json.startsWith("<")) {
            //可能传输过来的是xml
            return null;
        }

        JsonNode root = null;
        try {
            root = JsonMapper.getInstance().readTree(json);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (root == null || root.size() == 0) {
            return null;
        }
        Document document = DocumentHelper.createDocument();
        document.setXMLEncoding(charset);
        boolean hasRoot = true;
        if (root.size() != 1) {
            hasRoot = false;
            document.setRootElement(document.addElement(DecodeKey.RootName));
        }
        jsonToDocument(root, document, document.getRootElement());

        // 对于原来而言，是直接返回xml，但是有的地方比较恶心，全部同级
        String result = null;
        if (!hasRoot) {
            if (headerFlag) {
                result = document.getRootElement().asXML();
            } else {
                result = document.getRootElement().asXML();
            }
            result = result.replaceAll("<" + DecodeKey.RootName + ">", "").replaceAll("</" + DecodeKey.RootName + ">",
                    "");
        } else {
            if (headerFlag) {
                result = document.asXML();
            } else {
                result = document.getRootElement().asXML();
            }
        }
        return result;
    }

    private static void jsonToDocument(JsonNode rootNode, Document document, Element rootElement) {

        Iterator<String> keys = rootNode.fieldNames();

        JsonNode o;
        String key;
        while (keys.hasNext()) {
            key = keys.next();
            o = rootNode.path(key);

            /*
             * 如果是数组
             */
            if (o.isArray()) {
                Element arrayElement = rootElement.addElement(key);
                for (int i = 0; i < o.size(); i++) {
                    jsonToDocument(o.get(i), null, arrayElement);
                    // 没得法，完全是兼容
                    if (i < o.size() - 1) {
                        arrayElement = rootElement.addElement(key);
                    }
                }
            }
            /*
             * 如果是一个map
             */
            else if (o.isObject()) {
                if (rootElement == null) {
                    rootElement = document.addElement(key);
                    jsonToDocument(o, null, rootElement);
                } else {
                    Element objectElement = rootElement.addElement(key);
                    jsonToDocument(o, null, objectElement);
                }
            }
            /*
             * 最后应该是一个值
             */
            else {
                Element element = rootElement.addElement(key);
                element.setText(o.asText());
            }
        }
    }

    /**
     * 根据key找到对应的节点值,如果嵌套了很多层出现重复的暂时未处理，值获取第一层
     *
     * @param xml
     * @param key
     * @return
     */
    public static String findValueByXml(String xml, String key) {
        try {
            Document document = DocumentHelper.parseText(xml);

            return findValueByXml(document.getRootElement(), key);
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    private static String findValueByXml(Element rootElement, String key) {
        List<Element> childrenList = rootElement.elements();
        for (Element element : childrenList) {
            if (element.elements().isEmpty()) {
                if (StringUtils.equals(element.getName(), key)) {
                    return element.getStringValue();
                }
            } else {
                // 新加如果查询返回是同级参数，那么找到父亲节点就返回, 完全是为了兼容，这个地方配置估计也要处理
                if (StringUtils.equals(element.getName(), key)) {
                    String json = xmlToJson(element.asXML());
                    Map<String, Object> map = (Map<String, Object>) JsonMapper.fromJsonString(json, Map.class);
                    return jsonToXml(JsonMapper.toJsonString(map.get(key)));
                }
                return findValueByXml(element, key);
            }
        }
        return null;
    }
}
